#include "libauth.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "request.h"
#include <libipriv.h>

#include <syslog.h>
#include <ctype.h>

#include "gensess.h"


#define APP_NAME    "CyberTerm/1.0"


int urlenc(char* in,int size,char* out)
{
    if(!out) return 0;
    *out=0;
    if(!in) return 0;
    if(size<=0) size=strlen(in);
    int n=0;
    for(int i=0;i<size;i++)
    {
        if(isalnum(in[i])) {*out=in[i];out++;n++;}
        else
        {
            if(in[i]==' ') {*out='+';out++;n++;}
            else { int j = sprintf(out, "%%%.2X", (int) in[i]) ; out+=j ; n+=j;}
        }
    }
    *out=0;
    return n;
}


int strcopy(char* dst,char* src,int n)
{
    if(!dst || n<1) return 0;
    *dst=0;
    if(!src || !*src) return 0;
    n--;
    int m=strlen(src);
    m=n>m?m:n;
    strncpy(dst,src,m);
    dst[m]=0;
    return m;
}


char* strupr(char* src)
{
    char* ptr=src;
    while(*ptr)
    {
    if(*ptr>=97 && *ptr<=122)
        *ptr=(*ptr)-32;
    ptr++;
    }
    return src;
}

typedef unsigned short WORD;

typedef struct _SYSTEMTIME {
WORD wYear; 
WORD wMonth; 
WORD wDayOfWeek; 
WORD wDay; 
WORD wHour; 
WORD wMinute; 
WORD wSecond; 
WORD wMilliseconds; 
} SYSTEMTIME;


void GetLocalTime(SYSTEMTIME* st)
{
    struct tm stm;
    time_t t=time(0);
    memcpy(&stm,localtime(&t),sizeof(stm));
    st->wYear=stm.tm_year+1900;
    st->wMonth=stm.tm_mon+1;
    st->wDay=stm.tm_mday;
    st->wHour=stm.tm_hour;
    st->wMinute=stm.tm_min;
    st->wSecond=stm.tm_sec;
}

int CChecker_SignDocumentA(char*,char*,char*,char*,int,char**,int*);
int CChecker_CheckSignatureA(char*,char*,char*,char*,char*,int,char**,int*);
int CChecker_FreeCharBuffer(char*);



int CAuthServer::m_nCount=0;

CAuthServer::CAuthServer(void)
{
    *m_szProxy=0;
    strcpy(m_szAgent,APP_NAME);
    strcpy(m_szKeyPath,".\\");
    *m_szCodePhrase=0;
    strcpy(m_szSecretKeyFile,"secret.key");
    strcpy(m_szPublicKeyFile,"pubkeys.key");
    *m_szKeyNumber=0;
    *m_szBankKey=0;
    *m_szSD=0;
    *m_szAP=0;
    *m_szOP=0;

    Crypt_Init(0);
}

CAuthServer::~CAuthServer(void)
{
    Crypt_Done();
}

//Example: basic://login:passwd@server:3128
bool CAuthServer::SetProxy(char* uri)
{
    if (uri) {
        strncpy(m_szProxy, uri, sizeof(m_szProxy)-1);
        return true;
    } else
        return false;
}

bool CAuthServer::SetAgentName(char* name)
{
    strcopy(m_szAgent,name,MAX_AGENT_SIZE);
    return true;
}

bool CAuthServer::SetKeyPath(char* path)
{
    strcopy(m_szKeyPath,path,MAX_KEYPATH_SIZE);
    return true;
}

bool CAuthServer::SetCodePhrase(char* code)
{
    strcopy(m_szCodePhrase,code,MAX_CODEPHRASE_SIZE);
    return true;
}

bool CAuthServer::SetSecretKeyFile(char* file)
{
    strcopy(m_szSecretKeyFile,file,MAX_KEYFILE_SIZE);
    return true;
}

bool CAuthServer::SetPublicKeyFile(char* file)
{
    strcopy(m_szPublicKeyFile,file,MAX_KEYFILE_SIZE);
    return true;
}

bool CAuthServer::SetKeyNumber(char* num)
{
    strcopy(m_szKeyNumber,num,MAX_KEYNUM_SIZE);
    return true;
}

bool CAuthServer::SetBankKey(char* num)
{
    strcopy(m_szBankKey,num,MAX_KEYNUM_SIZE);
    return true;
}

bool CAuthServer::SetSD(char* code)
{
    strcopy(m_szSD,code,MAX_CODE_SIZE);
    return true;
}

bool CAuthServer::SetAP(char* code)
{
    strcopy(m_szAP,code,MAX_CODE_SIZE);
    return true;
}

bool CAuthServer::SetOP(char* code)
{
    strcopy(m_szOP,code,MAX_CODE_SIZE);
    return true;
}


int CAuthServer::SendRequest(char* uri,char* request,char* answer,int size)
{
    if(!uri || !*uri || !request || !*request || !answer || size<=0)
        return AERR_BADARGS;

    *answer=0;

    char buf[MAX_REQ_SIZE] = "inputmessage=";
    int t = strlen(buf);
    urlenc(request, 0, buf+t);

    char *tmp;
    int res = SendHttpRequest(m_szAgent, uri, m_szProxy, buf, strlen(buf), &tmp);

    if (res > 0) {
        snprintf(answer, size, "%s", tmp);
        FreeHttpAnswer(tmp);
        return ASUCCESS;
    }
    else
        return res;
}


int CAuthServer::SendRequestEx(char* uri,char* request,char* answer,int size)
{
    if(answer || size>0) *answer=0;
    if(!request) request="";
    char* ppOutputData=0;
    int pnOutputDataSize=0;

    if(CChecker_SignDocumentA(m_szKeyPath,m_szCodePhrase,m_szSecretKeyFile,
        request,strlen(request),&ppOutputData,&pnOutputDataSize) || !ppOutputData)
            return AERR_MAKESIGNATURE;

    char tmp[MAX_REQ_SIZE];
    int res=SendRequest(uri,ppOutputData,tmp,MAX_REQ_SIZE);
    CChecker_FreeCharBuffer(ppOutputData);
    if(res!=ASUCCESS) return res;


    if(CChecker_CheckSignatureA(m_szKeyPath,m_szPublicKeyFile,m_szKeyNumber,
        m_szBankKey,tmp,strlen(tmp),&ppOutputData,&pnOutputDataSize) || !ppOutputData)
            return AERR_CHECKSIGNATURE;
    size--;
    size=size>pnOutputDataSize?pnOutputDataSize:size;
    memcpy(answer,ppOutputData,size);
    answer[size]=0;
    CChecker_FreeCharBuffer(ppOutputData);

    return ASUCCESS;
}

int CAuthServer::PhoneCheck(char* uri,char* phone,char* amount,char* session,
        char* opname,char* account,char* errmsg)
{
    if (!phone) phone = "";
    if (!amount) amount = "1";
    if (session) *session = 0;
    if (opname) *opname = 0;
    if (errmsg) *errmsg = 0;
    char tmp[TMP_SIZE];
    char tmp2[TMP_SIZE];

    GenSessionId(tmp2);

    if(account)
    {
            sprintf(tmp,"SD=%s\r\nAP=%s\r\nOP=%s\r\nSESSION=%s\r\nNUMBER=%s\r\nACCOUNT=%s\r\nAMOUNT=%s\r\n",
                m_szSD,m_szAP,m_szOP,tmp2,phone,account,amount);
        *account=0;
    }else
    {
        sprintf(tmp,"SD=%s\r\nAP=%s\r\nOP=%s\r\nSESSION=%s\r\nNUMBER=%s\r\nAMOUNT=%s\r\n",
                m_szSD,m_szAP,m_szOP,tmp2,phone,amount);
    }
    int res = SendRequestEx(uri,tmp,tmp2,TMP_SIZE);
    if (res != ASUCCESS) return res;

    CRequest req;
    req.LoadVariables(tmp2,"");
    if (atoi(req.GetValue(0, "RESULT", "1")) != 0)
        return atoi(req.GetValue(0, "ERROR", "-3"));

    if(session) strcpy(session,req.GetValue(0,"SESSION"));
    if(opname) strcpy(opname,req.GetValue(0,"OPNAME"));
    if(account) strcpy(account,req.GetValue(0,"ACCOUNT"));
    if(errmsg) strcpy(errmsg,req.GetValue(0,"ERRMSG"));
    return ASUCCESS;
}

int CAuthServer::SendPay(char* uri,char* phone,char* amount,char* session,char* account)
{
    if(!phone) phone="";
    if(!amount) amount="1";
    if(!account) account="";
    char tmp[TMP_SIZE];
    char tmp2[TMP_SIZE];

    if(!session || !*session)
    {
        GenSessionId(tmp2);
        sprintf(tmp,"SD=%s\r\nAP=%s\r\nOP=%s\r\nSESSION=%s\r\nNUMBER=%s\r\nACCOUNT=%s\r\nAMOUNT=%s\r\n",
            m_szSD,m_szAP,m_szOP,tmp2,phone,account,amount);
    }
    else
        sprintf(tmp,"SD=%s\r\nAP=%s\r\nOP=%s\r\nSESSION=%s\r\nNUMBER=%s\r\nACCOUNT=%s\r\nAMOUNT=%s\r\n",
            m_szSD,m_szAP,m_szOP,session,phone,account,amount);

    int res = SendRequestEx(uri,tmp,tmp2,TMP_SIZE);
    if (res != ASUCCESS) return res;



    CRequest req;
    req.LoadVariables(tmp2,"");
    if (atoi(req.GetValue(0, "RESULT", "1")) != 0)
        return atoi(req.GetValue(0, "ERROR", "-3"));

    return ASUCCESS;
}

int CAuthServer::GetStatus(char* uri, char* session, int* state)
{
    if(!session) session="";
    if(state) *state=0;
    char tmp[TMP_SIZE];
    char tmp2[TMP_SIZE];

    sprintf(tmp, "SESSION=%s\r\n", session);
    int res = SendRequestEx(uri,tmp,tmp2,TMP_SIZE);
    if (res != ASUCCESS) return res;

    CRequest req;
    req.LoadVariables(tmp2, "");
    if (state)
        *state = atoi(req.GetValue(0, "RESULT", "0"));
    return atoi(req.GetValue(0, "ERROR", "-3"));
}
